/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

namespace DaveSexton.DocProject.Sandcastle.Configuration
{
	public sealed class PathsElement : ConfigurationElement, IDisposable
	{
		#region Public Properties
		[ConfigurationProperty("root", DefaultValue = "%DXROOT%", IsRequired = false)]
		[StringValidator(MinLength = 1)]
		public string Root
		{
			get
			{
				return GetValue("root");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["root"] = value;
			}
		}

		[ConfigurationProperty("fxReflectionDataRoot", DefaultValue = @"Data\Reflection\", IsRequired = false)]
		[StringValidator(MinLength = 1)]
		public string ReflectionDataRoot
		{
			get
			{
				return GetValue(Root, "fxReflectionDataRoot");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["fxReflectionDataRoot"] = value;
			}
		}

		[ConfigurationProperty("mRefBuilderConfig", IsRequired = true)]
		public string MRefBuilderConfig
		{
			get
			{
				return GetValue(Root, "mRefBuilderConfig");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["mRefBuilderConfig"] = value;
			}
		}

		[ConfigurationProperty("transforms", IsRequired = true)]
		public string Transforms
		{
			get
			{
				return GetValue(Root, "transforms");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["transforms"] = value;
			}
		}

		[ConfigurationProperty("presentation", IsRequired = true)]
		public string Presentation
		{
			get
			{
				return GetValue(Root, "presentation");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["presentation"] = value;
			}
		}

		[ConfigurationProperty("sharedPresentation", IsRequired = true)]
		public string SharedPresentation
		{
			get
			{
				return GetValue(Root, "sharedPresentation");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["sharedPresentation"] = value;
			}
		}

		[ConfigurationProperty("tools", IsRequired = true)]
		public string Tools
		{
			get
			{
				return GetValue(Root, "tools");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["tools"] = value;
			}
		}

		[ConfigurationProperty("schemas", IsRequired = true)]
		public string Schemas
		{
			get
			{
				return GetValue(Root, "schemas");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["schemas"] = value;
			}
		}

		public string ToolsUnexpanded
		{
			get
			{
				return GetValue(Root, "tools", false);
			}
		}

		[ConfigurationProperty("htmlHelpWorkshop", DefaultValue = @"%ProgramFiles%\Html Help Workshop\hhc.exe", IsRequired = false)]
		[StringValidator(MinLength = 1)]
		public string HtmlHelpWorkshop
		{
			get
			{
				return GetValue("htmlHelpWorkshop");
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				settings["htmlHelpWorkshop"] = value;
			}
		}
		#endregion

		#region Private / Protected
		private readonly IsolatedSettingsDictionary<string, string> settings;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="PathsElement" /> class.
		/// </summary>
		public PathsElement()
		{
			settings = new IsolatedSettingsDictionary<string, string>(
				System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForAssembly(), GetType(),
				System.Globalization.CultureInfo.InvariantCulture, StringComparer.OrdinalIgnoreCase);
		}
		#endregion

		#region Methods
		public void SaveChanges()
		{
			settings.Save();
		}

		private string GetValue(string propertyName)
		{
			return GetValue(propertyName, true);
		}

		private string GetValue(string propertyName, bool expandEnvironmentVariables)
		{
			string path =
				((settings.ContainsKey(propertyName))
					? settings[propertyName]
					: (settings.IsCommitted(propertyName))
						? settings.GetCommittedValue(propertyName)
						: base[propertyName] as string)
				?? string.Empty;

			if (expandEnvironmentVariables)
				return Environment.ExpandEnvironmentVariables(path);
			else
				return path;
		}

		private string GetValue(string basePath, string propertyName)
		{
			return GetValue(basePath, propertyName, true);
		}

		private string GetValue(string basePath, string propertyName, bool expandEnvironmentVariables)
		{
			string path =
				((settings.ContainsKey(propertyName))
					? settings[propertyName]
					: (settings.IsCommitted(propertyName))
						? settings.GetCommittedValue(propertyName)
						: base[propertyName] as string)
				?? string.Empty;

			path = System.IO.Path.Combine(basePath, path);

			if (expandEnvironmentVariables)
				return Environment.ExpandEnvironmentVariables(path);
			else
				return path;
		}
		#endregion

		#region IDisposable Members
		/// <summary>
		/// Releases all resources used by an instance of the <see cref="PathsElement" /> class.
		/// </summary>
		/// <remarks>
		/// This method calls the virtual <see cref="Dispose(bool)" /> method, passing in <strong>true</strong>, and then suppresses 
		/// finalization of the instance.
		/// </remarks>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Releases unmanaged resources before an instance of the <see cref="PathsElement" /> class is reclaimed by garbage collection.
		/// </summary>
		/// <remarks>
		/// This method releases unmanaged resources by calling the virtual <see cref="Dispose(bool)" /> method, passing in <strong>false</strong>.
		/// </remarks>
		~PathsElement()
		{
			Dispose(false);
		}

		/// <summary>
		/// Releases the unmanaged resources used by an instance of the <see cref="PathsElement" /> class and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing"><strong>true</strong> to release both managed and unmanaged resources; <strong>false</strong> to release only unmanaged resources.</param>
		private void Dispose(bool disposing)
		{
			if (disposing)
				settings.Dispose();
		}
		#endregion
	}
}
